added SSCLI 1.0
[windows-sources.git] / shared source / wpf / src / host / shimimpl / bindstatuscallback.cxx
blob5b3d1d1fe897c6fd7e2f02f86fde6fe5844334ae
1 //+-----------------------------------------------------------------------
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // Description:
6 // Implements the BindStatusCallback class of PresentationHost.
7 //
8 // History
9 // 2002/06/22-murrayw
10 // Created
11 // 2003/06/30-[....]
12 // Ported ByteRangeDownloader to WCP
13 // 2007/09/20-[....]
14 // Ported Windows->DevDiv. See SourcesHistory.txt.
16 //------------------------------------------------------------------------
18 #include "Precompiled.hxx"
19 #include "BindStatusCallback.hxx"
20 #include "HostShim.hxx"
21 #include "ShimUtilities.hxx"
23 #if DEBUG
24 static WCHAR * rgBS_Notifications[] =
26 L"no data",
27 L"BINDSTATUS_FINDINGRESOURCE",
28 L"BINDSTATUS_CONNECTING",
29 L"BINDSTATUS_REDIRECTING",
30 L"BINDSTATUS_BEGINDOWNLOADDATA",
31 L"BINDSTATUS_DOWNLOADINGDATA",
32 L"BINDSTATUS_ENDDOWNLOADDATA",
33 L"BINDSTATUS_BEGINDOWNLOADCOMPONENTS",
34 L"BINDSTATUS_INSTALLINGCOMPONENTS",
35 L"BINDSTATUS_ENDDOWNLOADCOMPONENTS",
36 L"BINDSTATUS_USINGCACHEDCOPY",
37 L"BINDSTATUS_SENDINGREQUEST",
38 L"BINDSTATUS_CLASSIDAVAILABLE",
39 L"BINDSTATUS_MIMETYPEAVAILABLE",
40 L"BINDSTATUS_CACHEFILENAMEAVAILABLE",
41 L"BINDSTATUS_BEGINSYNCOPERATION",
42 L"BINDSTATUS_ENDSYNCOPERATION",
43 L"BINDSTATUS_BEGINUPLOADDATA",
44 L"BINDSTATUS_UPLOADINGDATA",
45 L"BINDSTATUS_ENDUPLOADDATA",
46 L"BINDSTATUS_PROTOCOLCLASSID",
47 L"BINDSTATUS_ENCODING",
48 L"BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE",
49 L"BINDSTATUS_CLASSINSTALLLOCATION",
50 L"BINDSTATUS_DECODING",
51 L"BINDSTATUS_LOADINGMIMEHANDLER",
52 L"BINDSTATUS_CONTENTDISPOSITIONATTACH",
53 L"BINDSTATUS_FILTERREPORTMIMETYPE",
54 L"BINDSTATUS_CLSIDCANINSTANTIATE",
55 L"BINDSTATUS_IUNKNOWNAVAILABLE",
56 L"BINDSTATUS_DIRECTBIND",
57 L"BINDSTATUS_RAWMIMETYPE",
58 L"BINDSTATUS_PROXYDETECTING",
59 L"BINDSTATUS_ACCEPTRANGES",
60 L"BINDSTATUS_COOKIE_SENT",
61 L"BINDSTATUS_COMPACT_POLICY_RECEIVED",
62 L"BINDSTATUS_COOKIE_SUPPRESSED",
63 L"BINDSTATUS_COOKIE_STATE_UNKNOWN",
64 L"BINDSTATUS_COOKIE_STATE_ACCEPT",
65 L"BINDSTATUS_COOKIE_STATE_REJECT",
66 L"BINDSTATUS_COOKIE_STATE_PROMPT",
67 L"BINDSTATUS_COOKIE_STATE_LEASH",
68 L"BINDSTATUS_COOKIE_STATE_DOWNGRADE",
69 L"BINDSTATUS_POLICY_HREF",
70 L"BINDSTATUS_P3P_HEADER",
71 L"BINDSTATUS_SESSION_COOKIE_RECEIVED",
72 L"BINDSTATUS_PERSISTENT_COOKIE_RECEIVED",
73 L"BINDSTATUS_SESSION_COOKIES_ALLOWED",
74 L""
76 #endif // DEBUG
78 //******************************************************************************
80 // CBindStatusCallback::CBindStatusCallback
82 //******************************************************************************
84 CBindStatusCallback::CBindStatusCallback()
86 DPF(8, _T("CBindStatusCallback::CBindStatusCallback(%08X)"), this);
88 m_nObjRefCount = 0;
89 m_pStream = NULL;
90 m_pflb = NULL;
91 m_nBytesTotal = 0;
92 m_nBytesRead = 0;
93 m_fTerminatedFLB = FALSE;
94 m_Mime = MimeType_Unknown;
95 m_pib = NULL;
96 m_hrBindResult = S_FALSE;
99 m_hMimeArrivedEvent = ::CreateEvent(
100 NULL, // Default security, not inherited.
101 TRUE, // Manual reset event.
102 FALSE, // Initially unsignaled.
103 NULL // No name.
106 m_hManifestAvailableEvent = ::CreateEvent(
107 NULL, // Default security, not inherited.
108 TRUE, // Manual reset event.
109 FALSE, // Initially unsignaled.
110 NULL // No name.
113 ::ResetEvent(CHostShim::GetInstance()->GetDownloadCompletedEvent());
115 m_pDownloadInfo = NULL;
118 CBindStatusCallback::~CBindStatusCallback()
120 DPF(8, _T("CBindStatusCallback::~CBindStatusCallback(%08X)"), this);
122 if (m_hMimeArrivedEvent != NULL)
124 ::CloseHandle(m_hMimeArrivedEvent);
125 m_hMimeArrivedEvent = NULL;
128 if (m_hManifestAvailableEvent != NULL)
130 ::CloseHandle(m_hManifestAvailableEvent);
131 m_hManifestAvailableEvent = NULL;
134 ReleaseInterface(m_pStream);
135 ReleaseInterface(m_pflb);
137 //DASSERT(m_pib == NULL);
138 ReleaseInterface(m_pib);
141 //******************************************************************************
143 // CBindStatusCallback::QueryInterface(REFIID riid,
144 // LPVOID *ppReturn)
146 //******************************************************************************
148 STDMETHODIMP CBindStatusCallback::QueryInterface(REFIID riid,
149 __out LPVOID *ppReturn)
151 HRESULT hr = E_NOINTERFACE;
153 DPF(8, _T("CBindStatusCallback::QueryInterface(%08X)"), this);
155 *ppReturn = NULL;
157 if (riid == IID_IUnknown)
159 *ppReturn = this;
161 else if (riid == IID_IBindStatusCallback)
163 *ppReturn = this;
166 if (*ppReturn)
168 ((LPUNKNOWN)*ppReturn)->AddRef();
169 hr = S_OK;
172 return hr;
175 //******************************************************************************
177 // CBindStatusCallback::AddRef()
179 //******************************************************************************
181 STDMETHODIMP_(ULONG) CBindStatusCallback::AddRef()
183 m_nObjRefCount++;
184 DPF(10, _T("CBindStatusCallback::AddRef(%08X)- %d"), this, m_nObjRefCount);
185 return m_nObjRefCount;
188 //******************************************************************************
190 // CBindStatusCallback::Release()
192 //******************************************************************************
194 STDMETHODIMP_(ULONG) CBindStatusCallback::Release()
196 m_nObjRefCount--;
198 DPF(10, _T("CBindStatusCallback::Release(%08X)- %d"), this, m_nObjRefCount);
200 if (m_nObjRefCount == 0)
202 delete this;
203 return 0;
206 return m_nObjRefCount;
209 //******************************************************************************
211 // CBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding* pib)
213 //******************************************************************************
215 HRESULT CBindStatusCallback::OnStartBinding(DWORD /* dwReserved */,
216 __in IBinding* pib)
218 DPF(8, _T("CBindStatusCallback::OnStartBinding(%08X)"), this);
219 HRESULT hr = S_OK;
221 CK_PARG(pib);
223 m_pib = pib;
224 m_pib->AddRef();
226 Cleanup:
228 return hr;
231 //******************************************************************************
233 // CBindStatusCallback::GetPriority(LONG *pnPriority)
235 //******************************************************************************
237 HRESULT CBindStatusCallback::GetPriority(__out_opt LONG*)
239 DPF(8, _T("CBindStatusCallback::GetPriority(%08X)"), this);
241 // Applications that implement the IBindStatusCallback interface can return E_UNIMPL or
242 // S_OK if they are not interested in receiving this notification.
244 return E_NOTIMPL;
247 //******************************************************************************
249 // CBindStatusCallback::OnLowResource(DWORD dwReserved)
251 //******************************************************************************
253 HRESULT CBindStatusCallback::OnLowResource(DWORD) // dwReserved)
255 DPF(8, _T("CBindStatusCallback::OnLowResource(%08X)"), this);
256 return S_OK;
259 //******************************************************************************
261 // CBindStatusCallback::OnProgress(ULONG ulProgress,
262 // ULONG ulProgressMax,
263 // ULONG ulStatusCode,
264 // LPCWSTR szStatusText)
266 //******************************************************************************
268 HRESULT CBindStatusCallback::OnProgress(ULONG, // ulProgress,
269 ULONG ulProgressMax, //ulProgressMax
270 ULONG ulCode, // ulStatusCode,
271 LPCWSTR pszText) // szStatusText)
273 EventWriteWpfHostUm_BindProgress(ulCode, pszText);
275 HRESULT hr = S_OK;
277 switch (ulCode)
279 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
280 DPF(4, _T("CBindStatusCallback::OnProgress(%08X) - BINDSTATUS_CACHEFILENAMEAVAILABLE (%s) "), this, pszText);
281 m_cacheFilename.SetValue(pszText);
282 ResolveMimeTypeSecondChance(pszText);
283 break;
285 case BINDSTATUS_MIMETYPEAVAILABLE:
286 DPF(4, _T("CBindStatusCallback::OnProgress(%08X) - BINDSTATUS_MIMETYPEAVAILABLE"), this);
287 SetMimeTypeString(pszText);
288 m_Mime = GetMimeTypeFromString(pszText);
289 // DD Dev10 613556 - If a misconfigured web server returns an unknown MIME type,
290 // we'll get a second chance to try to map it back to a known MIME type based on
291 // the file extension, through ResolveMimeTypeSecondChance. This will set the
292 // event regardless of the outcome.
293 if (m_Mime != MimeType_Unknown)
295 ::SetEvent(m_hMimeArrivedEvent);
297 break;
299 case BINDSTATUS_BEGINDOWNLOADDATA:
300 DPF(4, _T("CBindStatusCallback::OnProgress(%08X) - BINDSTATUS_BEGINDOWNLOADDATA(%d)"), this, ulProgressMax);
301 m_nBytesTotal = ulProgressMax;
302 break;
304 case BINDSTATUS_ENDDOWNLOADDATA:
305 DPF(4, _T("CBindStatusCallback::OnProgress(%08X) - BINDSTATUS_ENDDOWNLOADDATA(%d)"), this, ulProgressMax);
306 break;
308 #if DEBUG
309 default:
310 DPF(4, _T("CBindStatusCallback::OnProgress(%08X) - %s [%d]"), this, rgBS_Notifications[ulCode], ulCode);
311 break;
312 #endif // DEBUG
315 return hr;
318 //******************************************************************************
320 // CBindStatusCallback::OnStopBinding(HRESULT hresult, LPCWSTR szError)
322 //******************************************************************************
324 HRESULT CBindStatusCallback::OnStopBinding(HRESULT hr, LPCWSTR szError)
326 DPF(8, _T("CBindStatusCallback::OnStopBinding(%08X) - %08X"), this, hr);
327 m_hrBindResult = hr; // Useful for Watson dump investigations.
328 EventWriteWpfHostUm_OnStopBinding(hr);
330 if (IsXps())
332 this->BindTerminated(hr);
335 if (m_pib)
337 m_pib->Release();
338 m_pib = NULL;
341 // Either on error or on success signal the events so that PersistMoniker can continue.
342 ::SetEvent(this->m_hMimeArrivedEvent);
343 ::SetEvent(this->m_hManifestAvailableEvent);
344 SignalAvalonStartupRelatedEvent(CHostShim::GetInstance()->GetDownloadCompletedEvent());
346 return hr;
349 //******************************************************************************
351 // CBindStatusCallback::GetBindInfo(DWORD* grfBINDF, BINDINFO* pbindinfo)
352 // Abstract:
353 // BINDF_ASYNCHRONOUS - Value that indicates that the moniker should return immediately
354 // from IMoniker::BindToStorage or IMoniker::BindToObject. The actual
355 // result of the bind to an object or the bind to storage arrives
356 // asynchronously. The client is notified through calls to its
357 // IBindStatusCallback::OnDataAvailable or
358 // IBindStatusCallback::OnObjectAvailable method. If the client does
359 // not specify this flag, the bind operation will be synchronous, and
360 // the client will not receive any data from the bind operation until
361 // the IMoniker::BindToStorage or IMoniker::BindToObject call returns.
363 // BINDF_ASYNCSTORAGE - Value that indicates the client application calling the
364 // IMoniker::BindToStorage method prefers that the storage and stream
365 // objects returned in IBindStatusCallback::OnDataAvailable return
366 // E_PENDING when they reference data not yet available through their
367 // read methods, rather than blocking until the data becomes available.
368 // This flag applies only to BINDF_ASYNCHRONOUS operations. Note that
369 // asynchronous stream objects return E_PENDING while data is still
370 // downloading and return S_FALSE for the end of the file.
372 // BINDF_PULLDATA - Value that indicates the asynchronous moniker allows the client of
373 // IMoniker::BindToStorage to drive the bind operation by pulling the data,
374 // rather than having the moniker drive the operation by pushing the data
375 // to the client. When this flag is specified, new data is only read/downloaded
376 // after the client finishes downloading all data that is currently available.
377 // This means data is only downloaded for the client after the client does an
378 // IStream::Read operation that blocks or returns E_PENDING. When the client
379 // specifies this flag, it must be sure to read all the data it can, even data
380 // that is not necessarily available yet. When this flag is not specified, the
381 // moniker continues downloading data and calls the client with
382 // IBindStatusCallback::OnDataAvailable whenever new data is available. This
383 // flag applies only to BINDF_ASYNCHRONOUS bind operations.
385 //******************************************************************************
387 HRESULT CBindStatusCallback::GetBindInfo(__out DWORD* grfBINDF,
388 __out BINDINFO* pBindInfo)
390 DPF(8, _T("CBindStatusCallback::GetBindInfo(%08X)"), this);
391 HRESULT hr = S_OK;
393 CK_PARG(grfBINDF);
394 CK_PARG(pBindInfo);
396 *grfBINDF = BINDF_ASYNCHRONOUS
397 | BINDF_ASYNCSTORAGE
398 #ifdef DOCUMENT_SHIM
399 | BINDF_PULLDATA
400 #endif
403 pBindInfo->cbSize = sizeof(BINDINFO);
404 pBindInfo->szExtraInfo = NULL;
405 pBindInfo->grfBindInfoF = 0;
406 //!!! Make sure to set BINDINFO_OPTIONS_ENABLE_UTF8 in all implementations of IBindStatusCallback.
407 //!!! It is needed for correct encoding of non-ASCII characters in URL paths, per RFC 3986 & 3987.
408 pBindInfo->dwOptions = BINDINFO_OPTIONS_ENABLE_UTF8;
409 pBindInfo->dwBindVerb = BINDVERB_GET;
410 pBindInfo->szCustomVerb = NULL;
412 ::SecureZeroMemory(&pBindInfo->stgmedData, sizeof(STGMEDIUM));
414 Cleanup:
415 return hr;
418 //******************************************************************************
420 // CBindStatusCallback::OnDataAvailable(DWORD grfBSCF,
421 // DWORD dwSize,
422 // FORMATETC* pFormatetc,
423 // STGMEDIUM* pStgmed)
425 //******************************************************************************
427 HRESULT CBindStatusCallback::OnDataAvailable(DWORD grfBSCF,
428 DWORD dwSize,
429 __in FORMATETC* pFormatetc,
430 __in STGMEDIUM* pStgmed)
432 DPF(8, _T("CBindStatusCallback::OnDataAvailable(%08X) - (%d)"), this, dwSize);
433 HRESULT hr = S_OK;
435 CK_PARG(pFormatetc);
436 CK_PARG(pStgmed);
438 // if this is not a container, jump out.
439 if (!IsXps())
441 goto Cleanup;
444 //DASSERT(dwSize <= m_nBytesTotal);
446 // on first notification, cache stream handle.
447 if (grfBSCF & BSCF_FIRSTDATANOTIFICATION)
449 // make sure the type is an IStream
450 if ( (pStgmed->tymed == TYMED_ISTREAM) &&
451 (pStgmed->pstm != NULL) )
453 //DASSERT(m_pStream == NULL);
454 m_pStream = pStgmed->pstm;
455 m_pStream->AddRef();
459 // only read if we have a valid cached stream and
460 // we have not already read to the end.
461 if ( (m_pStream != NULL) && (m_nBytesTotal > m_nBytesRead) )
463 ULONG cbRead;
464 ULONG cbWritten;
465 BYTE pbArray[IO_BUFFER_SIZE];
467 // sit in loop reading stream until we are either at the end or
468 // we need to wait for more data
469 for(;;)
471 cbWritten = 0;
472 cbRead = 0;
473 hr = m_pStream->Read((void *)pbArray, sizeof(pbArray), &cbRead);
475 if (SUCCEEDED(hr) || (hr == E_PENDING) )
477 // if we read something, track the movement
478 if (cbRead > 0)
480 m_nBytesRead += cbRead;
481 m_pflb->FillAppend((void *)pbArray, cbRead, &cbWritten);
483 //DASSERT(cbRead == cbWritten);
486 // handle termination
487 if (m_nBytesTotal == m_nBytesRead)
489 this->BindTerminated();
492 // we have reached the end, usually denoted by S_FALSE
493 if (hr == S_FALSE)
495 DPF(4, _T("CBindStatusCallback::OnDataAvailable(%08X) - EOS (%d, %d)"), this, m_nBytesRead, dwSize);
496 hr = S_OK;
497 break;
500 // if E_PENDING is returned, get out.
501 // we will get another call with more data.
502 if (hr == E_PENDING)
504 DPF(4, _T("CBindStatusCallback::OnDataAvailable(%08X) - Pos (%d, %d)"), this, m_nBytesRead, dwSize);
505 hr = S_OK;
506 break;
509 // if we failed, do not attempt another read. Return the failed hr
510 else if (FAILED(hr))
512 break;
517 // on last notification, release stream
518 if (grfBSCF & BSCF_LASTDATANOTIFICATION)
520 ReleaseInterface(m_pStream);
521 m_pStream = NULL;
524 Cleanup:
525 return hr;
528 //******************************************************************************
530 // CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown* punk)
532 //******************************************************************************
534 HRESULT CBindStatusCallback::OnObjectAvailable(REFIID riid, __in IUnknown* punk)
536 DPF(8, _T("CBindStatusCallback::OnObjectAvailable(%08X)"), this);
537 HRESULT hr = S_OK;
539 CK_PARG(punk);
541 Cleanup:
543 return hr;
546 //******************************************************************************
548 // CBindStatusCallback::BindTerminated()
550 //******************************************************************************
552 void CBindStatusCallback::BindTerminated()
554 this->BindTerminated(E_FAIL);
557 //******************************************************************************
559 // CBindStatusCallback::BindTerminated(HRESULT hr)
561 //******************************************************************************
563 void CBindStatusCallback::BindTerminated(HRESULT hr)
565 if (!m_fTerminatedFLB)
567 m_fTerminatedFLB = TRUE;
568 m_pflb->Terminate(SUCCEEDED(hr) ? TRUE: FALSE);
570 // Signal the download completed event.
571 SignalAvalonStartupRelatedEvent(CHostShim::GetInstance()->GetDownloadCompletedEvent());
574 //******************************************************************************
576 // CBindStatusCallback::ResolveMimeTypeSecondChance()
578 //******************************************************************************
580 void CBindStatusCallback::ResolveMimeTypeSecondChance(LPCWSTR pszLocalFile)
582 // DD Dev10 613556 - Some misconfigured web servers return an unknown MIME type during
583 // the BINDSTATUS_MIMETYPEAVAILABLE binding phase. This second chance logic uses UrlMon
584 // functionality to map the file name of the local download location onto a CLSID which
585 // we can use to map back to the MIME type. In practice, UrlMon uses the file extension
586 // to perform this mapping in the absence of additional information.
588 if (m_Mime == MimeType_Unknown)
590 CLSID clsId;
592 HRESULT hr = GetClassFileOrMime(0, pszLocalFile, 0, 0, 0, 0, &clsId);
593 if (SUCCEEDED(hr))
595 if (IsEqualCLSID(clsId, CLSID_DocObjXapp))
597 m_Mime = MimeType_Application;
599 else if (IsEqualCLSID(clsId, CLSID_DocObjXaml))
601 m_Mime = MimeType_Markup;
605 ::SetEvent(m_hMimeArrivedEvent);